/*
 *    Copyright © OpenAtom Foundation.
 *
 *    Licensed under the Apache License, Version 2.0 (the "License");
 *    you may not use this file except in compliance with the License.
 *    You may obtain a copy of the License at
 *
 *         http://www.apache.org/licenses/LICENSE-2.0
 *
 *    Unless required by applicable law or agreed to in writing, software
 *    distributed under the License is distributed on an "AS IS" BASIS,
 *    WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 *    See the License for the specific language governing permissions and
 *    limitations under the License.
 */

package com.inspur.edp.bef.bizentity;

import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
import com.fasterxml.jackson.databind.annotation.JsonSerialize;
import com.inspur.edp.bef.bizentity.beenum.BECategory;
import com.inspur.edp.bef.bizentity.beenum.BETriggerTimePointType;
import com.inspur.edp.bef.bizentity.beenum.GspDataLockType;
import com.inspur.edp.bef.bizentity.gspbusinessentity.entity.GspBeExtendInfo;
import com.inspur.edp.bef.bizentity.json.model.BizEntityDeserializer;
import com.inspur.edp.bef.bizentity.json.model.BizEntitySerializer;
import com.inspur.edp.bef.bizentity.operation.BizMgrAction;
import com.inspur.edp.bef.bizentity.operation.BizOperation;
import com.inspur.edp.bef.bizentity.operation.Determination;
import com.inspur.edp.bef.bizentity.operation.collection.BizMgrActionCollection;
import com.inspur.edp.bef.bizentity.operation.internalmgraction.DeleteMgrAction;
import com.inspur.edp.bef.bizentity.operation.internalmgraction.IInternalMgrAction;
import com.inspur.edp.bef.bizentity.operation.internalmgraction.ModifyMgrAction;
import com.inspur.edp.bef.bizentity.operation.internalmgraction.QueryMgrAction;
import com.inspur.edp.bef.bizentity.operation.internalmgraction.RetrieveDefaultMgrAction;
import com.inspur.edp.bef.bizentity.operation.internalmgraction.RetrieveMgrAction;
import com.inspur.edp.caf.cef.schema.structure.CommonStructure;
import com.inspur.edp.cef.designtime.api.IGspCommonField;
import com.inspur.edp.das.commonmodel.IGspCommonModel;
import com.inspur.edp.das.commonmodel.IGspCommonObject;
import com.inspur.edp.das.commonmodel.entity.GspCommonModel;
import com.inspur.edp.das.commonmodel.util.CommonModelExtension;
import com.inspur.edp.lcm.metadata.api.IMetadataContent;
import com.inspur.edp.lcm.metadata.api.entity.ProcessMode;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.function.Predicate;

/**
 * BE元数据实体类
 */
@JsonSerialize(using = BizEntitySerializer.class)
@JsonDeserialize(using = BizEntityDeserializer.class)
public class GspBusinessEntity extends GspCommonModel implements IMetadataContent {

  // region 属性
  public final GspBeExtendInfo getGspBeExtendInfo(ProcessMode type) {
    GspBeExtendInfo beExtendInfo = new GspBeExtendInfo();
    beExtendInfo.setId(this.getID());
    beExtendInfo.setConfigId(this.getGeneratedConfigID());
    beExtendInfo.setLastChangedOn(new Date());
    return beExtendInfo;
  }

  /**
   * 生成构件程序集名
   */
  private String privateComponentAssemblyName;

  public final String getComponentAssemblyName() {
    return privateComponentAssemblyName;
  }

  public final void setComponentAssemblyName(String value) {
    privateComponentAssemblyName = value;
  }

  /**
   * BE 实体类型
   */
  private BECategory privateCategory = BECategory.forValue(0);

  public BECategory getCategory() {
    return privateCategory;
  }

  public void setCategory(BECategory value) {
    privateCategory = value;
  }

  /**
   * BE根节点
   */
  public final GspBizEntityObject getMainObject() {
    return (GspBizEntityObject) super.getMainObject();
  }

  public final void setMainObject(GspBizEntityObject value) {

    super.setCmMainObject(value);
  }

  /**
   * 实体数据加锁类型 此属性影响到实体使用乐观锁或者悲观锁控制数据并发 默认为悲观锁，保证更好的数据一致性，同时可以提升用户体验。必须显式加锁才能编辑数据
   */
  private GspDataLockType privateDataLockType = GspDataLockType.forValue(0);

  public final GspDataLockType getDataLockType() {
    return privateDataLockType;
  }

  public final void setDataLockType(GspDataLockType value) {
    privateDataLockType = value;
  }

  /**
   * 扩展类型，固定返回BE类型，用于兼容
   */
  @Override
  public String getExtendType() {
    return "GspBusinessEntity";
  }

  private String dependentEntityId;
  private String dependentEntityName;
  private String dependentEntityPackageName;

  boolean isUsingTimeStamp;
  boolean enableCaching = false;
  boolean enableTreeDtm = true;
  private String cacheConfiguration = "";
  private boolean enableApproval = false;
  private boolean tccSupported = false;
  private boolean autoTccLock = true;
  private boolean autoComplete = true;
  private boolean autoCancel = true;

  /**
   * 是否启用TCC
   */
  public boolean isTccSupported() {
    return tccSupported;
  }

  public void setTccSupported(boolean tccSupported) {
    this.tccSupported = tccSupported;
  }

  /**
   * 是否自动添加TCC锁
   */
  public boolean isAutoTccLock() {
    return autoTccLock;
  }

  public void setAutoTccLock(boolean autoTccLock) {
    this.autoTccLock = autoTccLock;
  }

  /**
   * 是否启用自动完成
   */
  public boolean isAutoComplete() {
    return autoComplete;
  }

  public void setAutoComplete(boolean autoComplete) {
    this.autoComplete = autoComplete;
  }

  /**
   * 是否启用启动取消
   */
  public boolean isAutoCancel() {
    return autoCancel;
  }

  public void setAutoCancel(boolean autoCancel) {
    this.autoCancel = autoCancel;
  }

  /**
   * 被依赖实体的id
   */
  public String getDependentEntityId() {
    return dependentEntityId;
  }

  public void setDependentEntityId(String value) {
    dependentEntityId = value;
  }

  /**
   * 被依赖实体的名称
   */
  public String getDependentEntityName() {
    return dependentEntityName;
  }

  public void setDependentEntityName(String value) {
    dependentEntityName = value;
  }

  /**
   * 被依赖的实体包名
   */
  public String getDependentEntityPackageName() {
    return dependentEntityPackageName;
  }

  public void setDependentEntityPackageName(String value) {
    dependentEntityPackageName = value;
  }

  private BizMgrActionCollection beMgrActions;

  public final BizMgrActionCollection getBizMgrActions() {
    if (beMgrActions == null) {
      beMgrActions = new BizMgrActionCollection();
    }
    beMgrActions.setOwner(this.getMainObject());
    return beMgrActions;
  }

  public final void setBizMgrActions(BizMgrActionCollection value) {
    beMgrActions = value;
    beMgrActions.setOwner(this.getMainObject());
  }

  // private java.util.ArrayList<AuthorizationInfo> authorizations;

  /**
   * BE关联的权限对象ID集合
   *
   */
  // java.util.ArrayList<AuthorizationInfo> getAuthorizations()

  // public void setAuthorizations(java.util.ArrayList<AuthorizationInfo> value)

  /**
   * 是否生成时间戳字段（仅主表）
   */
  public boolean getIsUsingTimeStamp() {
    return isUsingTimeStamp;
  }

  public void setIsUsingTimeStamp(boolean value) {
    isUsingTimeStamp = value;
  }

  /**
   * 是否启用审批
   */
  public boolean getEnableApproval() {
    return enableApproval;
  }

  public void setEnableApproval(boolean value) {
    enableApproval = value;
  }

  /**
   * 缓存配置
   */
  public String getCacheConfiguration() {
    return cacheConfiguration;
  }

  public void setCacheConfiguration(String value) {
    cacheConfiguration = value;
  }

  /**
   * 是否启用缓存
   */
  public boolean getEnableCaching() {
    return enableCaching;
  }

  public void setEnableCaching(boolean value) {
    enableCaching = value;
  }

  /**
   * 是否启用树内置动作
   */
  public boolean getEnableTreeDtm() {
    return enableTreeDtm;
  }

  public void setEnableTreeDtm(boolean value) {
    enableTreeDtm = value;
  }

  // endregion

  // region Ctor
  public GspBusinessEntity() {
    getBizMgrActions().add(new QueryMgrAction());
    getBizMgrActions().add(new RetrieveDefaultMgrAction());
    getBizMgrActions().add(new RetrieveMgrAction());
    getBizMgrActions().add(new ModifyMgrAction());
    getBizMgrActions().add(new DeleteMgrAction());
  }
  // endregion

  // region 方法

  /**
   * 获取BE上所有的dbo
   *
   * @return
   */
  public final ArrayList<String> getAllDbos() {
    ArrayList<String> list = new ArrayList<>();
    for (GspBizEntityObject object : getAllNodes()) {
      list.add(object.getRefObjectName());
    }
    return list;
  }

  /**
   * 按照层次遍历的BE结点列表,先根遍历
   *
   * @return
   */
  public final java.util.ArrayList<GspBizEntityObject> getAllNodes() {
    ArrayList<IGspCommonObject> list = CommonModelExtension.getLevelOrderedNodes(this);
    ArrayList<GspBizEntityObject> bizObjs = new ArrayList<GspBizEntityObject>();
    for (IGspCommonObject item : list) {
      bizObjs.add((GspBizEntityObject) item);
    }
    return bizObjs;
  }

  /**
   * 查询符合条件的Node集合
   *
   * @param predicate 查询条件
   * @return 返回结果按照层次遍历顺序
   */
  public final ArrayList<GspBizEntityObject> getAllNodes(Predicate<GspBizEntityObject> predicate) {

    ArrayList<GspBizEntityObject> bizObjs = getAllNodes();
    ArrayList<GspBizEntityObject> result = new ArrayList<GspBizEntityObject>();
    for (GspBizEntityObject item : bizObjs) {
      if (predicate.test(item)) {
        result.add(item);
      }
    }
    return result;
  }

  /**
   * 查询符合条件的第一个节点
   *
   * @param predicate
   * @return
   */
  public final GspBizEntityObject getNode(Predicate<GspBizEntityObject> predicate) {
    ArrayList<GspBizEntityObject> result = getAllNodes(predicate);
    if (result.size() > 0) {
      return result.get(0);
    }
    return null;
  }

  /**
   * 查询指定Code的节点
   *
   * @param nodeCode
   * @return
   */
  public final GspBizEntityObject getNode(String nodeCode) {
    return getNode(pre -> pre.getCode().equals(nodeCode));
  }

  public final IGspCommonModel copyToCommonModel() {
    // TODO 后续换成Copy方法
    return this;
  }

  /**
   * 获取某一时机所有的Dtm，并按先子后主排序
   *
   * @param timePoint 执行时机
   * @return 如果找不到返回空集合
   */
  public final java.util.ArrayList<Determination> getAllDtmWithTriggerTime(
      BETriggerTimePointType timePoint) {
    java.util.ArrayList<Determination> dtms = new java.util.ArrayList<Determination>();
    java.util.Stack<GspBizEntityObject> bizObjecs = new java.util.Stack<GspBizEntityObject>();
    getBizObjectFromChildToParent(new java.util.ArrayList<GspBizEntityObject>(
        java.util.Arrays.asList(new GspBizEntityObject[]{getMainObject()})), bizObjecs);
    while (bizObjecs.size() > 0) {
      ArrayList<Determination> list = bizObjecs.pop().getDeterminations()
          .getFiltedDtms(dtm -> dtm.getTriggerTimePointType().contains(timePoint));
      dtms.addAll(list);
    }
    return dtms;
  }

  /**
   * 获取所有的节点，按先子后主的顺序
   *
   * @param childObjects
   * @param bizObjects
   */
  private void getBizObjectFromChildToParent(java.util.ArrayList<GspBizEntityObject> childObjects,
      java.util.Stack<GspBizEntityObject> bizObjects) {
    if (childObjects.size() > 0) {
      java.util.ArrayList<GspBizEntityObject> childs = new java.util.ArrayList<GspBizEntityObject>();
      for (IGspCommonObject obj : childObjects) {
        GspBizEntityObject item = (GspBizEntityObject) obj;
        bizObjects.push(item);

        for (IGspCommonObject childObj : item.getContainChildObjects()) {
          childs.add((GspBizEntityObject) childObj);
        }
      }
      getBizObjectFromChildToParent(childs, bizObjects);
    }
  }

  /**
   * 合并自模板实体
   *
   * @param dependentEntity 模板实体
   */
  public final void mergeWithDependentEntity(GspBusinessEntity dependentEntity) {
    mergeWithDependentEntity(dependentEntity, false);
  }

  public final void mergeWithDependentEntity(GspBusinessEntity dependentEntity, boolean isInit) {
    if (dependentEntity.getCategory() != BECategory.DependentBusinessEntity) {
      throw new RuntimeException("Exception");
    }
    // 初始化dbe带出主对象
    getMainObject().setIsRef(true);

    getMainObject().mergeWithDependentObject(dependentEntity.getMainObject(), isInit);
    mergeMgrActions(dependentEntity);
  }

  private void mergeMgrActions(GspBusinessEntity dependentEntity) {
    getBizMgrActions().mergeDbeOperations(dependentEntity.getBizMgrActions());
  }

  /**
   * 克隆
   *
   * @return
   */
  public GspBusinessEntity clone() {
    GspBusinessEntity be = (GspBusinessEntity) super.clone();
    if (be == null) {
      return null;
    }
    if (getBizMgrActions() != null) {
      Object tempVar = getBizMgrActions().clone();
      be.setBizMgrActions(
          (BizMgrActionCollection) ((tempVar instanceof BizMgrActionCollection) ? tempVar : null));
    }
    return be;
  }

  // endregion

  // region IEntityObject.GetRefStructures
  @Override
  protected List<CommonStructure> getCommonModelRefStructures() {
    List<IGspCommonField> fields = new ArrayList<>();
    for (IGspCommonField field : getAllElementList(false)) {
      fields.add(field);
    }
    return null;
  }

  /**获取除内置外的所有外部方法*/
  public BizMgrActionCollection getCustomMgrActions() {
    BizMgrActionCollection mgrActions = new BizMgrActionCollection();
    for (BizOperation operation : this.getBizMgrActions()) {
      if (operation instanceof IInternalMgrAction) {
        continue;
      }
      mgrActions.add((BizMgrAction) operation);
    }
    return mgrActions;
  }
  // endregion
}
